import tkinter as tk
from tkinter import messagebox, simpledialog, Toplevel, ttk, Frame
import json
from models import Library, Student, Book
from library import (load_books, load_students, borrow_book, return_book, 
                    search_books, reserve_book, generate_statistics)

def main():
    library = Library()
    load_books(library, 'resource/books.json')
    load_students(library, 'resource/students.json')

class LibraryApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Library Management System")
        self.root.geometry("800x600")
        self.root.configure(bg='#f0f0f0')
        self.library = Library()
        self.status_message = tk.StringVar()
        self.status_message.set("Ready")

        self.load_data('resource/books.json')
        self.load_data('resource/students.json')

        self.create_widgets()
        self.status_message = tk.StringVar()
        self.status_message.set("Ready")

    def create_widgets(self):
        self.create_top_frame()
        self.create_middle_frame()
        self.create_bottom_frame()
        self.create_menu()

#the ui interface    
    def create_top_frame(self):
        top_frame = ttk.LabelFrame(self.root, text="User Information", padding="10")
        top_frame.pack(fill="x", padx=10, pady=5)

 #use student id and book id to sign in
        ttk.Label(top_frame, text="Student Name:").grid(row=0, column=0, padx=5, pady=5)
        self.student_name_entry = ttk.Entry(top_frame)
        self.student_name_entry.grid(row=0, column=1, padx=5, pady=5)

        ttk.Label(top_frame, text="Book ID:").grid(row=1, column=0, padx=5, pady=5)
        self.book_id_entry = ttk.Entry(top_frame)
        self.book_id_entry.grid(row=1, column=1, padx=5, pady=5)

# find the sctudent id from their name
        ttk.Label(top_frame, text="Student ID:").grid(row=0, column=2, padx=5, pady=5)
        self.student_id_var = tk.StringVar(value="-")
        self.student_id_label = ttk.Label(top_frame, textvariable=self.student_id_var)
        self.student_id_label.grid(row=0, column=3, padx=5, pady=5)
        ttk.Button(top_frame, text="Find ID", command=self.lookup_student_id).grid(row=0, column=4, padx=5, pady=5)

       
    def create_middle_frame(self):
        middle_frame = ttk.LabelFrame(self.root, text="Operations", padding="10")
        middle_frame.pack(fill="x", padx=10, pady=5)

#the operation buttons
        operations_frame = ttk.Frame(middle_frame)
        operations_frame.pack(fill="x", expand=True)

        button_configs = [
            ("Borrow Book", self.borrow_book),
            ("Return Book", self.return_book),
            ("Reserve Book", self.reserve_book),
            ("Search Books", self.search_books),
            ("Add Book", self.add_book),
            ("Add Student", self.add_student),
            ("View Statistics", self.show_statistics)
        ]

        for i, (text, command) in enumerate(button_configs):
            col = i % 3
            row = i // 3
            ttk.Button(operations_frame, text=text, command=command).grid(
                row=row, column=col, padx=5, pady=5, sticky="ew"
            )
            operations_frame.grid_columnconfigure(col, weight=1)

    def create_bottom_frame(self):
        bottom_frame = ttk.Frame(self.root, padding="10")
        bottom_frame.pack(fill="x", side="bottom", padx=10, pady=5)

        status_bar = ttk.Label(bottom_frame, textvariable=self.status_message)
        status_bar.pack(fill="x")

#the menu
    def create_menu(self):
        menu = tk.Menu(self.root)
        self.root.config(menu=menu)

        file_menu = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label="File", menu=file_menu)
        file_menu.add_command(label="Exit", command=self.root.quit)

        operations_menu = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label="Operations", menu=operations_menu)
        operations_menu.add_command(label="Borrow Book", command=self.borrow_book)
        operations_menu.add_command(label="Return Book", command=self.return_book)
        operations_menu.add_command(label="Search Books", command=self.search_books)
        operations_menu.add_command(label="Reserve Book", command=self.reserve_book)
        operations_menu.add_command(label="View Statistics", command=self.show_statistics)

    def load_data(self, file_path):
        try:
            if 'books.json' in file_path:
                load_books(self.library, file_path)
            elif 'students.json' in file_path:
                load_students(self.library, file_path)
        except FileNotFoundError:
            self.show_error("File not found.")
        except json.JSONDecodeError:
            self.show_error("Invalid JSON format.")

    def show_error(self, message):
        messagebox.showerror("Error", message)
        self.status_message.set(f"Error: {message}")

    def show_success(self, message):
        messagebox.showinfo("Success", message)
        self.status_message.set(message)

    def add_book(self):
        top = Toplevel(self.root)
        top.title("Add Book")
        top.geometry("400x300")
        top.configure(bg='#f0f0f0')

        frame = ttk.LabelFrame(top, text="Book Information", padding="10")
        frame.pack(fill="both", expand=True, padx=10, pady=5)

# book information entries
        fields = [("Title:", "title"), ("Authors:", "authors")]
        entries = {}

        for i, (label, key) in enumerate(fields):
            ttk.Label(frame, text=label).grid(row=i, column=0, padx=5, pady=5)
            entry = ttk.Entry(frame)
            entry.grid(row=i, column=1, padx=5, pady=5, sticky="ew")
            entries[key] = entry

        ttk.Button(
            frame, 
            text="Add", 
            command=lambda: self.add_book_to_library(
                entries["title"].get(), 
                entries["authors"].get()
            )
        ).grid(row=len(fields), column=0, columnspan=2, pady=10)

    def add_book_to_library(self, title, authors):
        if not title or not authors:
            self.show_error("Title and authors are required.")
            return

        book_id = title.replace(' ', '_').lower()
        new_book = Book(
            title=title,
            authors=authors.split(", "),
            publisher="Unknown",
            year=2024,
            category="Unknown",
            sub_category="Unknown",
            language="Unknown",
            page_count=0,
            keywords=[],
            summary="Unknown",
            number_of_copies=1,
            available_copies=1
        )
        self.library.catalog[book_id] = new_book
        self.show_success(f"Book '{title}' added successfully.")

    def add_student(self):
        top = Toplevel(self.root)
        top.title("Add Student")
        top.geometry("400x300")
        top.configure(bg='#f0f0f0')

        frame = ttk.LabelFrame(top, text="Student Information", padding="10")
        frame.pack(fill="both", expand=True, padx=10, pady=5)

        fields = [
            ("Full Name:", "fullName"),
            ("School:", "school"),
            ("Age:", "age")
        ]
        entries = {}

        for i, (label, key) in enumerate(fields):
            ttk.Label(frame, text=label).grid(row=i, column=0, padx=5, pady=5)
            entry = ttk.Entry(frame)
            entry.grid(row=i, column=1, padx=5, pady=5, sticky="ew")
            entries[key] = entry

        ttk.Button(
            frame,
            text="Add",
            command=lambda: self.add_student_to_library(
                entries["fullName"].get(),
                entries["school"].get(),
                entries["age"].get()
            )
        ).grid(row=len(fields), column=0, columnspan=2, pady=10)

    def add_student_to_library(self, full_name, school, age):
        try:
            username = full_name.replace(' ', '_').lower()
            new_student = Student(
                fullName=full_name,
                school=school,
                age=int(age),
                borrowed_books=[],
                credits=3
            )
            self.library.student_records[username] = new_student
            self.show_success(f"Student '{full_name}' added successfully.")
        except ValueError:
            self.show_error("Please enter a valid age.")

    def lookup_student_id(self):
        """Look up student ID by name or create a new one"""
        name = self.student_name_entry.get().strip()
        if not name:
            self.show_error("Please enter a student name")
            return

# search for existing students
        student_id = None
        for sid, student in self.library.student_records.items():
            if student.fullName.lower() == name.lower():
                student_id = sid
                break

        if student_id:
            self.student_id_var.set(student_id)
            self.status_message.set(f"Found student ID: {student_id}")
        else:
            self.show_error(f"No student found with name: {name}")

    def borrow_book(self):
        student_name = self.student_name_entry.get()
        book_id = self.book_id_entry.get()
        if not student_name or not book_id:
            self.show_error("Please enter both Student Name and Book ID.")
            return
        
# management of check out/in
        student_id = student_name.replace(' ', '_').lower()
        if student_id not in self.library.student_records:
            self.show_error(f"No student found with name: {student_name}")
            return
            
        borrow_book(self.library, student_id, book_id)
        self.status_message.set(f"Attempting to borrow book {book_id}")

    def return_book(self):
        student_name = self.student_name_entry.get()
        book_id = self.book_id_entry.get()
        if not student_name or not book_id:
            self.show_error("Please enter both Student Name and Book ID.")
            return
            
        student_id = student_name.replace(' ', '_').lower()
        if student_id not in self.library.student_records:
            self.show_error(f"No student found with name: {student_name}")
            return
            
        return_book(self.library, student_id, book_id)
        self.status_message.set(f"Attempting to return book {book_id}")

    def search_books(self):
        search_title = simpledialog.askstring("Search", "Enter book title:")
        if not search_title:
            return
        
        search_results = search_books(self.library, title=search_title)
        
# create the results window
        results_window = Toplevel(self.root)
        results_window.title("Search Results")
        results_window.geometry("600x400")
        
# Create treeview
        tree = ttk.Treeview(results_window, columns=("Title", "Authors", "Available"), show="headings")
        tree.heading("Title", text="Title")
        tree.heading("Authors", text="Authors")
        tree.heading("Available", text="Available")
        
        for book in search_results:
            tree.insert("", "end", values=(
                book.title,
                ", ".join(book.authors),
                f"{book.available_copies}/{book.number_of_copies}"
            ))
        
        tree.pack(fill="both", expand=True, padx=10, pady=10)
        
        if not search_results:
            self.status_message.set("No books found.")
        else:
            self.status_message.set(f"Found {len(search_results)} books.")

    def reserve_book(self):
        student_name = self.student_name_entry.get()
        book_id = self.book_id_entry.get()
        if not student_name or not book_id:
            self.show_error("Please enter both Student Name and Book ID.")
            return
            
        # Generate student ID from name
        student_id = student_name.replace(' ', '_').lower()
        if student_id not in self.library.student_records:
            self.show_error(f"No student found with name: {student_name}")
            return
            
        reserve_book(self.library, student_id, book_id)
        self.status_message.set(f"Attempting to reserve book {book_id} for {student_name}")

    def show_statistics(self):
        stats = generate_statistics(self.library)
        
#  statistics window
        stats_window = Toplevel(self.root)
        stats_window.title("Library Statistics")
        stats_window.geometry("600x800")
        
        notebook = ttk.Notebook(stats_window)
        notebook.pack(fill="both", expand=True, padx=10, pady=5)
        
        general_frame = ttk.Frame(notebook)
        notebook.add(general_frame, text="General Statistics")
        
        general_stats = f"""
        Total Books: {stats['total_books']}
        Available Books: {stats['available_books']}
        Total Students: {stats['total_students']}
        Active Borrowers: {stats['active_borrowers']}
        Average Books per Student: {stats['average_books_per_student']:.2f}
        Students with Low Credit (<2): {stats['students_with_low_credit']}
        """
        
        general_text = tk.Text(general_frame, wrap=tk.WORD, padx=10, pady=10)
        general_text.insert('1.0', general_stats)
        general_text.config(state='disabled')
        general_text.pack(fill="both", expand=True)
        
        # for most popular borrowed books 
        borrowed_frame = ttk.Frame(notebook)
        notebook.add(borrowed_frame, text="Most Borrowed Books")
        
        tree = ttk.Treeview(borrowed_frame, columns=("Title", "Borrowed", "Available"), show="headings")
        tree.heading("Title", text="Title")
        tree.heading("Borrowed", text="Times Borrowed")
        tree.heading("Available", text="Available Copies")
        
        for book_id, book_stats in stats['most_borrowed_books'].items():
            tree.insert("", "end", values=(
                book_stats['title'],
                book_stats['borrowed_count'],
                book_stats['available_copies']
            ))
        
        tree.pack(fill="both", expand=True, padx=10, pady=10)

if __name__ == "__main__":
    root = tk.Tk()
    style = ttk.Style()
    style.theme_use('clam')  
    app = LibraryApp(root)
    root.mainloop()

